home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / bing-1.1.3.lha / bing-1.1.3 / src / unix / icmp_ux.c < prev   
C/C++ Source or Header  |  1997-06-06  |  6KB  |  247 lines

  1. /* $Id$ */
  2.  
  3. /* Usual includes/declarations */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/types.h>
  8. #include <errno.h>
  9.  
  10. /* More specific includes/declarations */
  11. #include <sys/time.h>
  12.  
  13. /* Network includes/definitions */
  14.  
  15. #include <netdb.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in_systm.h>
  18. #include <netinet/in.h>
  19.  
  20. #ifdef linux
  21. /* Needed for IP structures */
  22. #include <endian.h>
  23. #endif
  24.  
  25. /* These come either from the compatibility library or from the
  26.  * standard libraries.
  27.  */
  28. #include <netinet/ip.h>
  29. #include <netinet/ip_icmp.h>
  30.  
  31. #include "mod_icmp.h"
  32.  
  33. typedef struct {
  34.     int s;            /* Raw socket fd */
  35.     short id;            /* 16 bit id to be put in the echo request */
  36.     struct timeval last_send;    /* date of last send */
  37.     struct timeval timeout;    /* timeout for replies */
  38.     fd_set fds;            /* Precomputed fd_set for select() */
  39. } mod_icmp_i;
  40.  
  41. #define to_mod_icmp(h)    ((mod_icmp_i*)(h))
  42.  
  43. /*
  44.  * tvsub --
  45.  *    Subtract 2 timeval structs:  out = out - in.
  46.  *    Out is assumed to be >= in.
  47.  */
  48. void tvsub(out, in)
  49.     register struct timeval *out, *in;
  50. {
  51.     if ((out->tv_usec -= in->tv_usec) < 0) {
  52.     --out->tv_sec;
  53.     out->tv_usec += 1000000;
  54.     }
  55.     out->tv_sec -= in->tv_sec;
  56. }
  57.  
  58. /*
  59.  * in_cksum --
  60.  *    Checksum routine for Internet Protocol family headers (C Version)
  61.  */
  62. static int in_cksum(addr, len)
  63.     u_short *addr;
  64.     int len;
  65. {
  66.     register int nleft = len;
  67.     register u_short *w = addr;
  68.     register int sum = 0;
  69.     u_short answer = 0;
  70.     
  71.     /*
  72.      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
  73.      * sequential 16 bit words to it, and at the end, fold back all the
  74.      * carry bits from the top 16 bits into the lower 16 bits.
  75.      */
  76.     while (nleft > 1)  {
  77.     sum += *w++;
  78.     nleft -= 2;
  79.     }
  80.     
  81.     /* mop up an odd byte, if necessary */
  82.     if (nleft == 1) {
  83.     *(u_char *)(&answer) = *(u_char *)w ;
  84.     sum += answer;
  85.     }
  86.     
  87.     /* add back carry outs from top 16 bits to low 16 bits */
  88.     sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  89.     sum += (sum >> 16);            /* add carry */
  90.     answer = ~sum;                /* truncate to 16 bits */
  91.     return(answer);
  92. }
  93.  
  94. icmp_handle icmp_open()
  95. {
  96.     struct protoent *proto;
  97.     int s;
  98.     mod_icmp_i *new;
  99.     
  100.     if (!(proto = getprotobyname("icmp"))) {
  101.     fprintf(stderr, "unknown protocol icmp.\n");
  102.     return NULL;
  103.     }
  104.     
  105.     /*
  106.      * Open a raw socket
  107.      */
  108.     if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  109.     perror("socket");
  110.     return NULL;
  111.     }
  112.     
  113.     /*
  114.      * Everything ok, alloc our private state
  115.      */
  116.     new = (mod_icmp_i *)malloc(sizeof(mod_icmp_i));
  117.     if (new == NULL) {
  118.     close(s);
  119.     fprintf(stderr, "out of memory!\n");
  120.     return NULL;
  121.     }
  122.     new->s = s;
  123.     new->id = getpid() & 0xFFFF;
  124.     
  125.     FD_ZERO(&new->fds);
  126.     FD_SET(new->s, &new->fds);
  127.     
  128.     return (icmp_handle)new;
  129. }
  130.  
  131. int icmp_set_option(handle,level,optname,optval,optlen)
  132.     icmp_handle handle;
  133.     int level;
  134.     int optname;
  135.     void *optval;
  136.     int optlen;
  137. {
  138.     return setsockopt(to_mod_icmp(handle)->s, level, optname,
  139.               optval, optlen);
  140. }
  141.  
  142. void icmp_set_timeout(handle,timeout)
  143.     icmp_handle handle;
  144.     unsigned long timeout;
  145. {
  146.     mod_icmp_i *h = to_mod_icmp(handle);
  147.     
  148.     h->timeout.tv_sec = timeout / 1000000;
  149.     h->timeout.tv_usec = timeout % 1000000;
  150. }
  151.  
  152. unsigned short icmp_get_id(handle)
  153.     icmp_handle handle;
  154. {
  155.     mod_icmp_i *h = to_mod_icmp(handle);
  156.     
  157.     return h->id;
  158. }
  159.  
  160. int icmp_send(handle,msg,msg_size,to_addr,to_addr_size)
  161.     icmp_handle handle;
  162.     void *msg;
  163.     int msg_size;
  164.     struct sockaddr *to_addr;
  165.     int to_addr_size;
  166. {
  167.     mod_icmp_i *h = to_mod_icmp(handle);
  168.     
  169.     struct icmp *icmp_header;
  170.     
  171.     /* Fill-in the last bits in the icmp message */
  172.     icmp_header = (struct icmp *)msg;
  173.     icmp_header->icmp_id = h->id;
  174.     
  175.     /* Compute the checksum */
  176.     icmp_header->icmp_cksum = 0;
  177.     icmp_header->icmp_cksum = in_cksum((u_short *)msg, msg_size);
  178.     
  179.     /* Get the send date as late as possible */
  180.     gettimeofday(&h->last_send, (struct timezone *)NULL);
  181.     
  182.     /* Send packet and return to caller */
  183.     return sendto(h->s, 
  184.           (char *)msg, msg_size, 
  185.           0, 
  186.           (struct sockaddr *)to_addr, to_addr_size);
  187. }
  188.  
  189. int icmp_recv(handle,buf,buflen,from_addr,from_addr_size,elapsed)
  190.     icmp_handle handle;
  191.     char *buf;
  192.     int buflen;
  193.     struct sockaddr *from_addr;
  194.     int *from_addr_size;
  195.     double *elapsed;
  196. {
  197.     mod_icmp_i *h = to_mod_icmp(handle);
  198.     
  199.     int cc;
  200.     int rsel;
  201.     struct timeval tv, selw;
  202.     
  203.     /*
  204.      * Note that we can spare rebuilding the FD mask each time,
  205.      * since it will only be altered if select() times out, in which
  206.      * case we exit anyway...
  207.      */
  208.     FD_SET(h->s, &h->fds);
  209.     
  210.     /* Set timeout */
  211.     selw = h->timeout;
  212.     
  213.     /* Wait */
  214.     rsel = select(h->s+1, &h->fds,
  215.           (fd_set *)0, (fd_set *)0, &selw);
  216.     
  217.     /* Get date as soon as possible */
  218.     gettimeofday(&tv, (struct timezone *)NULL);
  219.     
  220.     /* Compute the elapsed time since last icmp_send */
  221.     tvsub(&tv, &h->last_send);
  222.     *elapsed = ((double)tv.tv_sec * 1e3) + ((double)tv.tv_usec / 1e3);
  223.     
  224.     if (rsel > 0) {
  225.     /* Got a reply packet, read it and return it */
  226.     cc = recvfrom(h->s, buf, buflen, 0, from_addr, from_addr_size);
  227.     return cc;
  228.     } else if (rsel == 0) {
  229.     /* Time out */
  230.     return 0;
  231.     } else if (errno == EINTR) {
  232.     return -1;
  233.     } else {
  234.     perror("select");
  235.     exit(1);
  236.     }
  237. }
  238.  
  239. int icmp_close(handle)
  240.     icmp_handle handle;
  241. {
  242.     mod_icmp_i *h = to_mod_icmp(handle);
  243.     close(h->s);
  244.     free(h);
  245.     return 0;
  246. }
  247.